home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 17
/
CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso
/
CUCD
/
Programming
/
DiceSource
/
src
/
dc1
/
genmisc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-09
|
44KB
|
1,838 lines
/*
* (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
* use is allowed under the terms of the DICE-LICENSE FILE,
* DICE-LICENSE.TXT.
*/
/*
* GENMISC.C
*
* Miscellanious stuff and some of the more esoteric generation routines
* such as -> . &lvalue [], etc...
*/
#include "defs.h"
Prototype void GenCast(Exp **);
Prototype void GenSizeof(Exp **);
Prototype void GenAddr(Exp **);
Prototype void GenInd(Exp **);
Prototype void GenPreInc(Exp **);
Prototype void GenPreDec(Exp **);
Prototype void GenIntConst(Exp **);
Prototype void GenStrConst(Exp **);
Prototype void GenFltConst(Exp **);
Prototype void GenVarRef(Exp **);
Prototype void GenCall(Exp **);
Prototype void GenCastArgs(Type *, Exp *, Exp **);
Prototype void GenPosInc(Exp **);
Prototype void GenPosDec(Exp **);
Prototype void GenStructInd(Exp **);
Prototype void GenStructElm(Exp **);
Prototype void GenArray(Exp **);
Prototype void GenBFExt(Exp **);
Prototype void BitFieldResultExp(Exp *);
Prototype void BitFieldResultType(Exp **, int);
Local void GenRegArgs(Exp *, char *, char *, ulong, char *, short);
Local void SaveCopyConflictsRegArgs(Exp *, char *, char *, ulong, short);
Local void FreeRegArgs(Exp *, char *);
Local long GenPushArgs(Exp *);
Local int PushArgExp(Exp *);
Local void InMaskPush(Exp *, char *);
Local void InMaskPop(char *);
/*
* GenCast()
*/
void
GenCast(pexp)
Exp **pexp;
{
Exp *exp = *pexp; /* left side exp, right side type */
Exp *e1;
Assert(exp->ex_Type);
if (GenPass == 0) {
if ((exp->ex_Flags & EF_ICAST) == 0) { /* see insert cast */
if (exp->ex_ExpL->ex_Type == NULL)
exp->ex_ExpL->ex_Type = exp->ex_Type; /* optimize */
CallLeft();
}
e1 = exp->ex_ExpL;
if (e1->ex_Stor.st_Type == ST_IntConst) {
e1->ex_Type = exp->ex_Type;
e1->ex_Stor.st_Size = e1->ex_Type->Size;
if (exp->ex_Type->Id == TID_FLT) {
e1->ex_Stor.st_FltConst = IntToFPStr(e1->ex_Stor.st_IntConst, e1->ex_Stor.st_Flags & SF_UNSIGNED, &e1->ex_Stor.st_FltLen);
e1->ex_Type = exp->ex_Type;
e1->ex_Stor.st_Size = e1->ex_Type->Size;
e1->ex_Stor.st_Type = ST_FltConst;
e1->ex_Token = TokFltConst;
e1->ex_Func = GenFltConst;
*pexp = e1;
return;
}
if (e1->ex_Type->Flags & TF_UNSIGNED) {
switch(e1->ex_Type->Size) {
case 0:
e1->ex_Stor.st_UIntConst = 0;
break;
case 1:
e1->ex_Stor.st_UIntConst = (ubyte)e1->ex_Stor.st_UIntConst;
break;
case 2:
e1->ex_Stor.st_UIntConst = (uword)e1->ex_Stor.st_UIntConst;
break;
case 4:
break;
default:
Assert(0);
}
e1->ex_Stor.st_Flags |= SF_UNSIGNED;
} else {
switch(e1->ex_Type->Size) {
case 0:
e1->ex_Stor.st_IntConst = 0;
break;
case 1:
e1->ex_Stor.st_IntConst = (char)e1->ex_Stor.st_IntConst;
break;
case 2:
e1->ex_Stor.st_IntConst = (short)e1->ex_Stor.st_IntConst;
break;
case 4:
break;
default:
yerror(exp->ex_LexIdx, EERROR_ILLEGAL_CAST);
break;
}
e1->ex_Stor.st_Flags &= ~SF_UNSIGNED;
}
*pexp = e1;
return;
}
/*
* Floating constant to integer
*
* e1->ex_StrConst e1->ex_StrLen
*/
if (e1->ex_Stor.st_Type == ST_FltConst) {
if (exp->ex_Type->Id == TID_FLT) { /* flt->flt no change */
*pexp = e1;
e1->ex_Type = exp->ex_Type;
return;
}
if (exp->ex_Type->Id == TID_INT) {
e1->ex_Stor.st_IntConst = FPStrToInt(e1, e1->ex_Stor.st_FltConst, e1->ex_Stor.st_FltLen);
e1->ex_Type = exp->ex_Type;
e1->ex_Stor.st_Size = e1->ex_Type->Size;
e1->ex_Stor.st_Type = ST_IntConst;
e1->ex_Token = TokIntConst;
e1->ex_Func = GenIntConst;
if (e1->ex_Stor.st_Size == 0) /* cast to void */
e1->ex_Stor.st_IntConst = 0;
*pexp = e1;
if (exp->ex_Type->Flags & TF_UNSIGNED)
exp->ex_Stor.st_Flags |= SF_UNSIGNED;
else
exp->ex_Stor.st_Flags &= ~SF_UNSIGNED;
return;
}
}
/*
* If Flt->Flt, Flt->Int, or Int->Flt conversion then
* set EF_CALL bit. (doesn't handle void case here)
*/
if (exp->ex_Type->Id == TID_FLT || e1->ex_Type->Id == TID_FLT) {
exp->ex_Flags |= EF_CALL;
GenFlagCallMade();
}
exp->ex_Flags |= e1->ex_Flags & EF_CALL;
} else {
Type *t = exp->ex_Type;
e1 = exp->ex_ExpL;
if (exp->ex_Flags & EF_RNU) {
e1->ex_Flags |= EF_RNU;
CallLeft();
return;
}
if (e1->ex_Type->Id == TID_ARY) {
CallLeft();
if (exp->ex_Flags & (EF_PRES|EF_ASSEQ)) {
CreateUnaryResultStorage(exp, 1);
asm_lea(exp, &e1->ex_Stor, 0, &exp->ex_Stor);
} else {
FreeStorage(&e1->ex_Stor);
/* X1 */
asm_getlea(exp, &e1->ex_Stor, &exp->ex_Stor);
}
return;
}
/*
* Floating point conversions fp -> int, int -> fp
*/
if (exp->ex_Type->Id == TID_FLT || e1->ex_Type->Id == TID_FLT) {
CallLeft();
CreateUnaryResultStorage(exp, 1);
if (exp->ex_Type->Id == TID_FLT) {
if (e1->ex_Type->Id == TID_FLT) { /* FLT -> FLT */
asm_fptofp(exp, &e1->ex_Stor, &exp->ex_Stor);
} else { /* INT -> FLT */
asm_inttofp(exp, &e1->ex_Stor, &exp->ex_Stor);
}
} else { /* FLT -> INT (if not cast to void) */
if (exp->ex_Stor.st_Size)
asm_fptoint(exp, &e1->ex_Stor, &exp->ex_Stor);
}
if (exp->ex_Type->Flags & TF_UNSIGNED)
exp->ex_Stor.st_Flags |= SF_UNSIGNED;
else
exp->ex_Stor.st_Flags &= ~SF_UNSIGNED;
return;
}
/*
* Bitfield Conversions
*
* XXX Enabled 23 Dec 95, Matt Dillon, to handle case where
* bitfield assignment occurs within expression and then must
* be extracted out again.
*/
if (exp->ex_Type->Id == TID_INT && e1->ex_Type->Id == TID_BITFIELD) {
CallLeft();
CreateUnaryResultStorage(exp, 1);
if (t->Flags & TF_UNSIGNED)
exp->ex_Stor.st_Flags |= SF_UNSIGNED;
else
exp->ex_Stor.st_Flags &= ~SF_UNSIGNED;
asm_bfext(exp, &e1->ex_Stor, &exp->ex_Stor);
return;
}
if ((exp->ex_Flags & (EF_PRES|EF_ASSEQ)) == 0) {
if (t->Size == e1->ex_Type->Size) {
CallLeft();
FreeStorage(&e1->ex_Stor);
ReuseStorage(&e1->ex_Stor, &exp->ex_Stor);
if (t->Flags & TF_UNSIGNED)
exp->ex_Stor.st_Flags |= SF_UNSIGNED;
else
exp->ex_Stor.st_Flags &= ~SF_UNSIGNED;
return;
}
}
/*
* If storage size is the same & storage passed down from parent
* then pass to subexp.
*/
if (t->Size == e1->ex_Type->Size && (exp->ex_Flags & EF_PRES) && (e1->ex_Flags & (EF_CRES|EF_ASSEQ)) == 0) {
e1->ex_Flags |= EF_PRES;
e1->ex_Stor = exp->ex_Stor;
if (e1->ex_Type->Flags & TF_UNSIGNED) /* ??? XXX */
e1->ex_Stor.st_Flags |= SF_UNSIGNED;
else
e1->ex_Stor.st_Flags &= ~SF_UNSIGNED;
CallLeft();
return;
}
CallLeft();
CreateUnaryResultStorage(exp, 1);
if (t->Flags & TF_UNSIGNED)
exp->ex_Stor.st_Flags |= SF_UNSIGNED;
else
exp->ex_Stor.st_Flags &= ~SF_UNSIGNED;
if (exp->ex_Stor.st_Size)
asm_ext(exp, &e1->ex_Stor, &exp->ex_Stor, e1->ex_Stor.st_Flags);
}
}
/*
* Strings use a dummy CharAryType ... not a real type because its size does
* not match the size of the string. So we hack the only operator that will
* ever need the size.
*/
void
GenSizeof(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
Type *type;
long size;
if (GenPass == 0) {
if (exp->ex_ExpL) {
Exp *e1;
CallLeft();
e1 = exp->ex_ExpL;
type = e1->ex_Type;
size = type->Size;
if (e1->ex_Stor.st_Type == ST_StrConst) {
DelStrList(e1->ex_Stor.st_Label);
size = e1->ex_Stor.st_StrLen;
}
} else {
type = exp->ex_Type;
size = type->Size;
if (size == 0)
{
if ((type->Id == TID_STRUCT) || (type->Id == TID_UNION))
Undefined_Tag(type, NULL, exp->ex_LexIdx);
else
yerror(exp->ex_LexIdx, EERROR_SIZEOF_TYPE_0);
}
}
exp->ex_ExpL = NULL;
AllocConstStor(&exp->ex_Stor, size, &LongType);
exp->ex_Type = &LongType;
exp->ex_Stor.st_Flags |= SF_NOSA;
exp->ex_Func = GenIntConst;
exp->ex_Flags |= EF_CRES;
}
}
void
GenAddr(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
Exp *e1;
CallLeft();
e1 = exp->ex_ExpL;
if (GenPass == 0) {
exp->ex_Flags |= e1->ex_Flags & EF_CALL;
if (e1->ex_Token == TokVarRef)
e1->ex_Var->Flags |= VF_ADDR;
#ifdef NOTDEF
if (e1->ex_Type->Id == TID_ARY) {
if (e1->ex_Stor.st_Type != ST_IntConst) /* no warning for offsetof() */
yerror(e1->ex_LexIdx, EWARN_ADDR_ARRAY_REDUNDANT);
exp->ex_Type = e1->ex_Type;
} else
#endif
if (e1->ex_Type->Id == TID_BITFIELD) {
yerror(e1->ex_LexIdx, EERROR_ADDR_BITFIELD_ILLEGAL);
} else {
exp->ex_Type = TypeToPtrType(e1->ex_Type);
}
exp->ex_Flags |= EF_CRES;
/*
* handle address of constant pointer, make it handlable as a
* constant expression.
*/
if (e1->ex_Stor.st_Type == ST_PtrConst) {
asm_getlea(exp, &e1->ex_Stor, &exp->ex_Stor);
#ifdef NOTDEF
exp->ex_Stor.st_Type = ST_IntConst;
exp->ex_Stor.st_IntConst = e1->ex_Stor.st_PtrConst;
#endif
exp->ex_Stor.st_Flags |= SF_NOSA;
exp->ex_Func = GenIntConst;
exp->ex_Flags |= EF_CRES;
if (exp->ex_Type->Id == TID_ARY)
exp->ex_Stor.st_Flags |= SF_LEA;
} else if (e1->ex_Stor.st_Type == ST_IntConst) {
exp->ex_Stor = e1->ex_Stor;
exp->ex_Stor.st_Flags &= ~SF_LEA;
}
} else {
if ((exp->ex_Flags & EF_RNU) == 0) {
if (e1->ex_Type->Id == TID_ARY) {
exp->ex_Stor = e1->ex_Stor;
} else {
FreeStorage(&e1->ex_Stor);
asm_getlea(exp, &e1->ex_Stor, &exp->ex_Stor);
}
} else {
FreeStorage(&e1->ex_Stor);
}
}
}
void
GenInd(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
Exp *e1;
CallLeft();
e1 = exp->ex_ExpL;
if (GenPass == 0) {
exp->ex_Type = e1->ex_Type;
exp->ex_Flags |= e1->ex_Flags & EF_CALL;
if (exp->ex_Type->Id != TID_PTR && exp->ex_Type->Id != TID_ARY) {
yerror(exp->ex_LexIdx, EERROR_INDIRECTION_NOT_PTR);
return;
}
exp->ex_Type = e1->ex_Type->SubType;
/*exp->ex_Flags |= EF_CRES;*/
} else {
FreeStorage(&e1->ex_Stor);
if ((exp->ex_Flags & EF_RNU) == 0) {
asm_getind(exp, e1->ex_Type, &e1->ex_Stor, &exp->ex_Stor, -1, -1, AutoResultStorage(exp));
}
return;
}
}
void
GenPreInc(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
Exp *e1;
CallLeft();
e1 = exp->ex_ExpL;
if (GenPass == 0) {
#ifdef NOTDEF
if (e1->ex_Stor.st_Type == ST_IntConst) {
e1->ex_Stor.st_IntConst = !e1->ex_Stor.st_IntConst;
e1->ex_Type = &LongType;
*pexp = e1;
return;
}
#endif
exp->ex_Type = e1->ex_Type;
exp->ex_Flags |= e1->ex_Flags & EF_CALL;
exp->ex_Flags |= EF_CRES;
if (e1->ex_Token == TokVarRef)
e1->ex_Var->RegFlags |= RF_MODIFIED;
if (e1->ex_Type->Id == TID_FLT) {
exp->ex_Flags |= EF_CALL;
GenFlagCallMade();
}
} else {
Stor con;
if (exp->ex_Type->Id == TID_FLT) {
AllocFltConstStor(&con, "1", 1, exp->ex_Type);
asm_fpadd(exp, exp->ex_Type, &con, &e1->ex_Stor, &e1->ex_Stor);
} else {
AllocConstStor(&con, AutoIncDecSize(e1), e1->ex_Type);
asm_add(exp, &con, &e1->ex_Stor, &e1->ex_Stor);
}
FreeStorage(&e1->ex_Stor);
if ((exp->ex_Flags & EF_RNU) == 0)
ReuseStorage(&e1->ex_Stor, &exp->ex_Stor);
}
}
void
GenPreDec(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
Exp *e1;
CallLeft();
e1 = exp->ex_ExpL;
if (GenPass == 0) {
#ifdef NOTDEF
if (e1->ex_Stor.st_Type == ST_IntConst) {
e1->ex_Stor.st_IntConst = !e1->ex_Stor.st_IntConst;
e1->ex_Type = &LongType;
*pexp = e1;
return;
}
#endif
exp->ex_Type = e1->ex_Type;
exp->ex_Flags |= e1->ex_Flags & EF_CALL;
exp->ex_Flags |= EF_CRES;
if (e1->ex_Token == TokVarRef)
e1->ex_Var->RegFlags |= RF_MODIFIED;
if (e1->ex_Type->Id == TID_FLT) {
exp->ex_Flags |= EF_CALL;
GenFlagCallMade();
}
} else {
Stor con;
if (exp->ex_Type->Id == TID_FLT) {
AllocFltConstStor(&con, "1", 1, exp->ex_Type);
asm_fpsub(exp, exp->ex_Type, &e1->ex_Stor, &con, &e1->ex_Stor);
} else {
AllocConstStor(&con, AutoIncDecSize(e1), e1->ex_Type);
asm_sub(exp, &e1->ex_Stor, &con, &e1->ex_Stor);
}
FreeStorage(&e1->ex_Stor);
if ((exp->ex_Flags & EF_RNU) == 0)
ReuseStorage(&e1->ex_Stor, &exp->ex_Stor);
}
}
/*
* GenIntConst()
*/
void
GenIntConst(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
if (GenPass == 0) {
Type *type;
long value = exp->ex_Stor.st_IntConst;
if (exp->ex_Stor.st_Flags & SF_UNSIGNED) {
type = &ULongType;
if ((unsigned long)value < 65536)
type = &UShortType;
if ((unsigned long)value < 256)
type = &UCharType;
} else {
type = &LongType;
if (value >= -32768 && value < 32768)
type = &ShortType;
if (value >= -128 && value < 128)
type = &CharType;
}
exp->ex_Type = type;
exp->ex_Flags |= EF_CRES;
AllocConstStor(&exp->ex_Stor, value, type);
} else {
exp->ex_Stor.st_Size = exp->ex_Type->Size;
if (exp->ex_Flags & EF_COND) {
exp->ex_Flags |= EF_CONDACK;
if (exp->ex_Cond >= 0 && exp->ex_Stor.st_IntConst)
asm_branch(exp->ex_LabelT);
if (exp->ex_Cond < 0 && !exp->ex_Stor.st_IntConst)
asm_branch(exp->ex_LabelF);
}
if (exp->ex_Type->Flags & TF_UNSIGNED)
exp->ex_Stor.st_Flags |= SF_UNSIGNED;
else
exp->ex_Stor.st_Flags &= ~SF_UNSIGNED;
}
}
void
GenStrConst(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
long l;
if (GenPass == 0) {
long iidx = -1; /* internationalization index */
l = AllocLabel();
exp->ex_Flags |= EF_CRES;
#ifdef COMMERCIAL
iidx = Internationalize(exp->ex_StrConst, exp->ex_StrLen);
#endif
AddStrList(exp->ex_StrConst, exp->ex_StrLen, l, iidx);
#ifdef COMMERCIAL
if (iidx >= 0) {
l = -l;
exp->ex_Type = &CharPtrType;
} else
#endif
{
exp->ex_Type = &CharAryType;
}
exp->ex_Stor.st_StrConst = exp->ex_StrConst;
exp->ex_Stor.st_StrLen = exp->ex_StrLen;
exp->ex_Stor.st_Type = ST_StrConst;
exp->ex_Stor.st_Flags = SF_NOSA;
exp->ex_Stor.st_Label = l;
} else {
#ifdef COMMERCIAL
if (exp->ex_Stor.st_Label < 0) {
exp->ex_Stor.st_Label = -exp->ex_Stor.st_Label;
exp->ex_Stor.st_Flags= 0;
exp->ex_Stor.st_Type = ST_RelLabel;
} else
#endif
{
exp->ex_Stor.st_Flags= SF_LEA;
exp->ex_Stor.st_Type = ST_RelLabel;
if (ConstCode)
exp->ex_Stor.st_Flags |= SF_CODE; /* in code section */
}
exp->ex_Stor.st_Size = PTR_SIZE;
exp->ex_Stor.st_Offset = 0;
}
}
void
GenFltConst(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
if (GenPass == 0) {
Assert(exp->ex_Type);
exp->ex_Flags |= EF_CRES;
AllocFltConstStor(&exp->ex_Stor, exp->ex_Stor.st_FltConst, exp->ex_Stor.st_FltLen, exp->ex_Type);
} else {
exp->ex_Stor.st_Size = exp->ex_Type->Size;
if (exp->ex_Flags & EF_COND) {
exp->ex_Flags |= EF_CONDACK;
if (exp->ex_Cond >= 0 && FltIsZero(exp, exp->ex_Stor.st_FltConst, exp->ex_Stor.st_FltLen))
asm_branch(exp->ex_LabelT);
if (exp->ex_Cond < 0 && !FltIsZero(exp, exp->ex_Stor.st_FltConst, exp->ex_Stor.st_FltLen))
asm_branch(exp->ex_LabelF);
}
#ifdef NOTDEF
/*
* Convert an fp string constant into a memory constant and change
* the storage type to label.
*/
asm_data_mask(0); XXX
asm_fltconst(&exp->ex_Stor, 1);
asm_code_mask(0); XXX
#endif
}
}
/*
* left side is ex_Var, a variable. Right side is ex_Symbol, a symbol.
*
* For array references we return the effective address of a pointer to
* the array. BUT, if the array is passed as an argument we return only
* a pointer to the array (since we can't get the eff.addr without generating
* code).
*
* If a register variable we have a problem... The register could have been
* forced and reused.
*
* __dynamic variables are automatically indirected through.
*/
void
GenVarRef(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
Var *var = exp->ex_Var;
if (GenPass == 0) {
Assert(var);
/*
* dynamic variables are automatically indirected
*/
#ifdef DYNAMIC
if ((var->Flags & TF_DYNAMIC) && (exp->ex_Flags & EF_DYNAMIC) == 0) {
exp->ex_Flags |= EF_DYNAMIC;
InsertNot(pexp);
exp = *pexp;
exp->ex_Func = GenInd;
(*exp->ex_Func)(pexp);
return;
}
#endif
exp->ex_Type = var->Type;
exp->ex_Flags |= EF_CRES;
exp->ex_Stor.st_Flags |= SF_VAR;
if (var->Type->Id == TID_PROC)
exp->ex_Type = TypeToPtrType(var->Type);
if (var->Type->Id == TID_ARY && (var->Flags & VF_ARG))
exp->ex_Type = TypeToPtrType(exp->ex_Type->SubType);
} else {
exp->ex_Stor = var->var_Stor;
exp->ex_Stor.st_Flags |= SF_VAR;
/*
* check for a change in type. In order to modify this
* expression's type without adding another expression node
* the type's Id and size may not be changed (see InsertCast())
*/
if (exp->ex_Type->Flags & TF_UNSIGNED)
exp->ex_Stor.st_Flags |= SF_UNSIGNED;
else
exp->ex_Stor.st_Flags &= ~SF_UNSIGNED;
if (var->Type->Id == TID_PROC) {
if (var->var_Stor.st_Type == ST_RelName) {
if (var->var_Stor.st_Name->Len == 6 && strncmp(var->var_Stor.st_Name->Name, "alloca", 6) == 0) {
yerror(exp->ex_LexIdx, EERROR_ALLOCA);
}
if (var->var_Stor.st_Name->Len == 12 && strncmp(var->var_Stor.st_Name->Name, "_dice_alloca", 12) == 0) {
ForceLinkFlag = 1;
puts("; FORCE LINK");
}
}
}
/*
* XXX - handling of registerized procedure name access
* ('@' or '_') -mR option. XXX
*/
#ifdef NOTDEF
if (var->Type->Flags & TF_REGCALLOK) {
if (RegCallOpt > 2 || (exp->ex_Flags & EF_DIRECT)) {
/* printf("VARFLAG = %08lx\n", var->Flags); */
if (IsRegCall(var->Flags)) {
exp->ex_Stor.st_Flags |= SF_REGARGS;
var->var_Stor.st_Flags |= SF_REGARGSUSED;
}
}
}
#endif
if (var->Type->Flags & TF_REGCALL) {
exp->ex_Stor.st_Flags |= SF_REGARGS;
var->var_Stor.st_Flags |= SF_REGARGSUSED;
}
if (exp->ex_Stor.st_Type == 0)
{
yerror(exp->ex_LexIdx, EERROR_ILLEGAL_ASSIGNMENT);
dbprintf(("var %s has no type!", SymToString(var->Sym)));
Assert(0);
}
#ifdef NOTDEF
if ((var->Flags & TF_EXTERN) && !(var->Flags & VF_DECLD)) {
AddExternList(var);
var->Flags |= VF_DECLD;
}
#endif
if ((var->Flags & VF_DECLD) == 0) {
if (var->Flags & TF_EXTERN)
AddExternList(var);
var->Flags |= VF_DECLD;
}
exp->ex_Stor.st_Size = exp->ex_Type->Size;
if (var->Type->Id == TID_ARY) {
if (var->Flags & VF_ARG) {
exp->ex_Stor.st_Size = PTR_SIZE;
} else {
exp->ex_Stor.st_Flags |= SF_LEA;
exp->ex_Stor.st_Size = PTR_SIZE;
}
}
if (var->Type->Id == TID_PROC) {
exp->ex_Stor.st_Flags |= SF_LEA; /* ptr to procedure */
exp->ex_Stor.st_Size = PTR_SIZE;
}
}
}
/*
* right side of call is an expression list rather than just an expression
*/
void
GenCall(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
Exp *e1;
if (GenPass == 0) {
Exp **pe = &exp->ex_ExpR;
Exp *e2;
Exp *en;
CallLeft();
e1 = exp->ex_ExpL;
while ((e2 = *pe) != NULL) {
en = e2->ex_Next;
(*e2->ex_Func)(pe);
(*pe)->ex_Next = en;
pe = &(*pe)->ex_Next;
}
#ifdef NOTDEF
if (e1->ex_Stor.st_Type == ST_IntConst) {
e1->ex_Stor.st_IntConst = !e1->ex_Stor.st_IntConst;
*pexp = e1;
return;
}
#endif
{
Type *t = e1->ex_Type;
if (t->Id == TID_PTR)
t = t->SubType;
if (t->Id != TID_PROC) {
yerror(e1->ex_LexIdx, EERROR_LHS_NOT_PROCEDURE);
exp->ex_Type = &LongType;
} else {
exp->ex_Type = t->SubType; /* return type of proc */
if (ProtoOnlyOpt && !(t->Flags & TF_PROTOTYPE))
yerror(e1->ex_LexIdx, EERROR_UNPROTOTYPED_CALL);
}
GenCastArgs(t, exp, &exp->ex_ExpR);
}
exp->ex_Flags |= EF_CALL;
GenFlagCallMade();
} else {
Stor *calls;
Stor ts;
short struct_ret;
PragNode *pragma_call;
Type *type = exp->ex_ExpL->ex_Type;
char prgno[16]; /* pragma register ordering */
if (type->Id == TID_PTR)
type = type->SubType;
Assert(type->Id == TID_PROC);
e1 = exp->ex_ExpL;
e1->ex_Flags |= EF_DIRECT;
if (type->SubType->Id == TID_STRUCT || type->SubType->Id == TID_UNION)
struct_ret = 1;
else
struct_ret = 0;
if (exp->ex_ExpL->ex_Token == TokVarRef) {
pragma_call = TestPragmaCall(exp->ex_ExpL->ex_Var, prgno);
if (pragma_call && (type->Flags & TF_PROTOTYPE) == 0)
yerror(exp->ex_LexIdx, EERROR_PROTO_REQUIRED_INLINE);
} else {
pragma_call = NULL;
}
if (pragma_call == NULL && (type->Flags & TF_REGCALL) == 0) {
/*
* STACK BASED CALL
*/
short autop;
long bytes;
if (exp->ex_ExpR)
bytes = GenPushArgs(exp->ex_ExpR);
else
bytes = 0;
if ((exp->ex_Flags & EF_STACK) && struct_ret == 0) {
exp->ex_Flags |= EF_STACKACK;
exp->ex_Flags |= EF_RNU;
autop = 1;
} else {
CreateUnaryResultStorage(exp, 0);
autop = 0;
}
/*
* Calculate call ea
*/
CallLeft();
e1 = exp->ex_ExpL;
calls = &e1->ex_Stor;
FreeStorage(&e1->ex_Stor);
if (e1->ex_Type->Id == TID_PTR) {
asm_getind(exp, e1->ex_Type, &e1->ex_Stor, &ts, -1, -1, 0);
calls = &ts;
FreeStorage(calls);
}
/*
* stack call, must clear SF_REGARGS so '_' label is used
*/
calls->st_Flags &= ~SF_REGARGS;
if (exp->ex_Flags & EF_RNU)
asm_call(exp, calls, exp->ex_Type, NULL, bytes, autop);
else
asm_call(exp, calls, exp->ex_Type, &exp->ex_Stor, bytes, autop);
} else {
/*
* REGISTERIZED PROCEDURE CALL
*
* (1) calculate those arguments whos register destinations
* do not conflict directly to the appropriate
* register destinations
*
* (2) calculate the call address to a temporary
*
* (3) calculate those arguments whos register destinations
* conflict, calculate them to non-conflicting temporary
* variables.
*
* (4) save registers in the conflict zone
*
* (5) move remaining temporary results to actual registers
*
* (6) make call (do not assign result storage yet)
*
* (7) restore registers in the conflict zone, move result
* storage elsewhere if it conflicts.
*
* (8) assign result storage
*/
ulong conMask; /* conflict mask */
ulong ignMask = -1; /* conflict save/restore mask */
char argno[16]; /* procedure call register ordering */
char actno[16]; /* actual regs for initial arg load */
char scReg[5]; /* scratch registers saved */
Stor res; /* result storage backing store */
short resBack = 0; /* backing store active */
scReg[0] = -1;
/*
* Generate result storage
*/
CreateUnaryResultStorage(exp, 0);
/*
* Generate a register list and a conflict mask. This call
* also sets the 'used' bit for the registers if it is not
* already set.
*/
conMask = RegCallOrder(type, argno, (pragma_call) ? prgno : NULL);
dbprintf((";conMask = %08lx\n", conMask));
/*
* Generate arguments for those bits that do not conflict with
* anything. The storage for these arguments will be locked.
*/
GenRegArgs(exp->ex_ExpR, argno, actno, ~conMask, scReg, 0);
/*
* If the result storage conflicts with a register and is
* not register-direct then we have to assign it to temporary
* storage first.
*
* If it is register direct (& conflict) then we do not have
* to assign it to temporary storage but must clear the
* conflict bit so we do not restore over our result
*
* Note that since the storage for the result in the case of
* a hard conflict is allocated after non-conflicting registers
* are allocated it will thus not conflict with anything and
* therefore not get restored over.
*/
if (RegisterMaskConflict(&exp->ex_Stor, conMask)) {
if (exp->ex_Stor.st_Type == ST_Reg) {
ignMask = ~(1 << exp->ex_Stor.st_RegNo);
} else {
res = exp->ex_Stor;
resBack = 1;
AllocAnyRegister(&exp->ex_Stor, exp->ex_Type, NULL);
}
}
/*
* Generate arguments for those bits that conflict with
* something. Results will be written to other temporary
* registers or pushed onto the stack, and locked.
*/
GenRegArgs(exp->ex_ExpR, argno, actno, conMask & ignMask, scReg, 1);
/*
* Generate call address to non-conflicting temporary
*
* If the call is a __libcall we offset it by the first
* argument.
*
* Otheriwse,
*
* If the call address is a pointer we have to resolve it,
* if the register conflicts with an argument we have to
* copy it to another register.
*
* We special case TID_PTR where the pointer is the same as
* the first argument in the call (the library base variable)
*
* XXX call address not guarenteed to be in non-conflicting
* register!
*/
InMaskPush(e1, scReg);
CallLeft();
e1 = exp->ex_ExpL;
calls = &e1->ex_Stor;
if (pragma_call) {
AllocRegisterAbs(&ts, RB_A6, 4);
ts.st_Type = ST_RelReg;
ts.st_Offset = -pragma_call->pn_Offset;
calls = &ts;
} else if (RegisterMaskConflict(calls, conMask)) {
AllocAddrRegister(&ts);
if (e1->ex_Type->Id == TID_PTR)
asm_move(exp, calls, &ts);
else
asm_lea(exp, calls, 0, &ts);
FreeStorage(&ts);
asm_getind(exp, &LongPtrType, &ts, &ts, -1, -1, 0);
FreeStorage(calls);
calls = &ts;
} else if (e1->ex_Type->Id == TID_PTR) {
asm_getind(e1, e1->ex_Type, &e1->ex_Stor, &ts, -1, -1, 0);
FreeStorage(calls);
calls = &ts;
}
/*
* Optimize result storage if it was a conflicting register,
* as well as prevent restoring over the result. We force
* the argument into the conflicted register (and do this last
* so there will be no further access to the now destructed
* register)
*/
if (ignMask != -1)
GenRegArgs(exp->ex_ExpR, argno, actno, ~ignMask, scReg, -1);
/*
* While calculating arguments or the call address if any
* subexpression had made a call we had to (and did) save
* any allocated scratch registers we need. We have to
* restore them here.
*/
InMaskPop(scReg);
/*
* Save conflicting variables and move already-generated
* arguments associated with said conflicts into their
* proper registers. (note: since this survives the call
* we cannot save conflicts into scratch registers)
*
* We do not save any variable that represents the result
* storage as this would cause the result storage to be
* overwritten on restore.
*/
SaveCopyConflictsRegArgs(exp->ex_ExpR, argno, actno, conMask & ignMask, 0);
/*
* Make the call
*/
FreeStorage(calls);
if (exp->ex_Flags & EF_RNU)
asm_call(exp, calls, exp->ex_Type, NULL, 0, 2);
else
asm_call(exp, calls, exp->ex_Type, &exp->ex_Stor, 0, 2);
/*
* Restore conflicted variables, either from other registers
* or off the stack.
*/
SaveCopyConflictsRegArgs(exp->ex_ExpR, argno, actno, conMask & ignMask, 1);
FreeRegArgs(exp->ex_ExpR, actno);
/*
* If the result would have conflicted we created a temporary
* for it and now must store it back after all other registers
* have been restored.
*/
if (resBack) {
FreeStorage(&exp->ex_Stor);
asm_move(exp, &exp->ex_Stor, &res);
exp->ex_Stor = res;
}
}
}
}
/*
* Generate arguments to registers. If tmpOk is 1 then argument
* will be generated to a temporary if the associated register is
* not available.
*
* Must handle case where char or short quantity is placed in an
* address register
*
* Must handle pragma case where extra register in argno/actno is the
* base register
*
* tmpOk
* -1 no, force register to be used even if a conflict
* 0 no, register must be free
* 1 yes
*/
void
GenRegArgs(
Exp *exp,
char *argno,
char *actno,
ulong mask,
char *scReg,
short tmpOk
) {
Stor t;
for (; exp; exp = exp->ex_Next, ++argno, ++actno) {
short rno = -1;
/*
* Do only the requested arguments
*/
if ((mask & (1 << *argno)) == 0)
continue;
/*printf(";GenRegArgs tmp = %d argno = %d RegAlloc=%08lx RegLocked=%08lx RegUsed=%08lx\n", tmpOk, *argno, RegAlloc, RegLocked, RegUsed);*/
/*
* Attempt to optimize destination register for the subexpression,
* but cannot do this if the subexpression contains a call
* (screws up register save & restore). Also, due to __dp calls
* D0 must be the last to be resolved. XXX ???
*
* Do not optimize ADDRESS REG destination if exptype size is not 4,
* don't think expression generation routines can handle it.
*/
if (*argno < RB_ADDR || exp->ex_Type->Size == 4) {
if ((exp->ex_Flags & (EF_CRES|EF_ASSEQ)) == 0 && !(exp->ex_Flags & EF_CALL)) {
if (tmpOk < 0)
rno = AllocRegisterAbs(&t, *argno, exp->ex_Type->Size);
else
rno = AttemptAllocRegisterAbs(&t, *argno, exp->ex_Type->Size);
exp->ex_Stor = t;
exp->ex_Flags |= EF_PRES;
}
}
InMaskPush(exp, scReg);
(*exp->ex_Func)(&exp);
if ((exp->ex_Flags & EF_PRES) == 0) {
if (((1 << *argno) & REGSCRATCH) == 0 && exp->ex_Stor.st_Type == ST_Reg && exp->ex_Stor.st_RegNo == *argno && exp->ex_Type->Size == exp->ex_Stor.st_Size) {
rno = *argno;
AllocRegisterAbs(&t, rno, exp->ex_Stor.st_Size);
} else {
FreeStorage(&exp->ex_Stor);
if (tmpOk < 0)
rno = AllocRegisterAbs(&t, *argno, exp->ex_Type->Size);
else
rno = AttemptAllocRegisterAbs(&t, *argno, exp->ex_Type->Size);
/*
* Hack the destination register size. Set to 2 if short
* or char type. Even though we are moving 'garbage'
* into the high bits of the register, the type sized bits
* will be correct.
*/
if (rno >= RB_ADDR && exp->ex_Type->Size < 4) {
exp->ex_Stor.st_Size = 2;
t.st_Size = 2;
}
asm_move_cast(exp, &exp->ex_Stor, &t);
}
}
*actno = rno;
/*printf(";GenRegArgs actual = %d\n", rno);*/
if ((1 << rno) & REGSCRATCH) {
short i;
for (i = 0; i < 4 && (short)(scReg[i] & 0x7F) != rno; ++i) {
if (scReg[i] == -1) {
scReg[i] = rno;
scReg[i+1] = -1;
break;
}
}
}
if (tmpOk <= 0 && rno != *argno)
{
dbprintf(("rno alloc failed %d/%d (%d)\n", rno, *argno, tmpOk));
Assert(0);
}
}
}
/*
* We have to save any scratch registers we have in use if the expression
* we are about to evaluate contains a call. We do not re-save registers
* which have already been saved.
*/
void
InMaskPush(exp, scReg)
Exp *exp;
char *scReg;
{
if (exp->ex_Flags & EF_CALL) {
short i;
char c;
for (i = 0; i < 4 && (c = scReg[i]) != -1; ++i) {
if ((c & 0x80) == 0) {
scReg[i] |= 0x80;
asm_push_mask(1 << c);
}
}
}
}
/*
* Before completing the call we have to pop any registers we had saved,
* and must be sure to pop them in the correct order.
*/
void
InMaskPop(scReg)
char *scReg;
{
short i;
char c;
for (i = 0; i < 4 && scReg[i] != -1; ++i)
;
for (--i; i >= 0; --i) {
if ((c = scReg[i]) & 0x80) {
asm_pop_mask(1 << (c & 0x7F));
}
}
}
/*
* Save conflicting registers while simultaniously moving the stored
* temporary into the conflicting register spot. The stored temporaries
* do not conflict with any of these registers.
*
* Only those registers represented by <mask> might conflict and are
* considered. If possible, we EXG the temporaries with the real
* registers. Otherwise we store the real registers on the stack and
* MOVE from the temporaries. On restore the opposite action occurs
*
* Since the register(s) are already allocated we can allocate/free
* without actually freeing them up.
*/
void
SaveCopyConflictsRegArgs(
Exp *expBase,
char *argno,
char *actno,
ulong mask,
short restore
) {
Stor t;
Stor a;
Exp *exp;
long regMask;
short i;
for (i = regMask = 0, exp = expBase; exp; exp = exp->ex_Next, ++i) {
if (mask & (1 << argno[i])) {
if ((1 << actno[i]) & REGSCRATCH) {
if (restore == 0)
regMask |= 1 << argno[i];
}
}
}
asm_push_mask(regMask);
for (i = regMask = 0, exp = expBase; exp; exp = exp->ex_Next, ++i) {
if (mask & (1 << argno[i])) {
AllocRegisterAbs(&t, argno[i], exp->ex_Stor.st_Size);
AllocRegisterAbs(&a, actno[i], exp->ex_Stor.st_Size);
/*
* AllocRegisterAbs() forces the size of an address register
* to 4 currently, XXX this is a hack
*/
if (exp->ex_Stor.st_Size < 4) {
t.st_Size = 2;
a.st_Size = 2;
}
if ((1 << actno[i]) & REGSCRATCH) {
if (restore) {
regMask |= 1 << argno[i];
} else {
asm_move(exp, &a, &t);
}
} else {
asm_exg(&a, &t);
}
FreeRegister(&a);
FreeRegister(&t);
}
}
asm_pop_mask(regMask);
}
/*
* Free registers allocated for the call arguments, clean up. Note
* that if we do not properly free arguments a software error, such
* as 'rno alloc failed' from the level above may occur.
*/
void
FreeRegArgs(exp, actno)
Exp *exp;
char *actno;
{
Stor t;
for (; exp; exp = exp->ex_Next, ++actno) {
AllocRegisterAbs(&t, *actno, exp->ex_Stor.st_Size);
FreeStorage(&t);
FreeStorage(&t);
}
}
Local long
GenPushArgs(exp)
Exp *exp;
{
long bytes;
if (exp->ex_Next)
bytes = GenPushArgs(exp->ex_Next);
else
bytes = 0;
return(bytes + PushArgExp(exp));
}
int
PushArgExp(exp)
Exp *exp;
{
exp->ex_Flags |= EF_STACK;
(*exp->ex_Func)(&exp);
if (exp->ex_Flags & EF_STACKACK) {
return(asm_stackbytes(exp->ex_Type));
} else {
FreeStorage(&exp->ex_Stor);
return(asm_push(exp, exp->ex_Type, &exp->ex_Stor));
}
}
void
GenCastArgs(type, cexp, pexp)
Type *type;
Exp *cexp;
Exp **pexp;
{
Exp *exp = *pexp;
short i;
/*
* if type->Args < 0 it is not a prototype, but that is ok the way
* our loop works.
*/
dbprintf((";%d args, flags = %08lx\n", type->Args, type->Flags));
for (i = 0; i < type->Args; ++i) {
Type *vtype;
if (exp == NULL || (exp->ex_Flags & EF_SPECIAL)) {
yerror(cexp->ex_LexIdx, EWARN_TOO_FEW_PARAMETERS);
break;
}
vtype = ActualPassType(type, type->Vars[i]->Type, 0);
dbprintf((";arg %d size=%ld argsize=%ld use=%ld\n", i, exp->ex_Type->Size, type->Vars[i]->Type->Size, vtype->Size));
if (exp->ex_Type != vtype) {
if (exp->ex_Type->Id == TID_INT && (vtype->Id == TID_INT || (exp->ex_Stor.st_Type == ST_IntConst && exp->ex_Stor.st_IntConst == 0))) {
InsertCast(pexp, vtype);
} else if (CheckConversion(exp, exp->ex_Type, vtype)) {
InsertCast(pexp, vtype); /* exp no longer valid */
}
}
exp = *pexp;
pexp = &exp->ex_Next;
exp = *pexp;
}
{
Exp *ex;
for (ex = exp; ex && (ex->ex_Flags & EF_SPECIAL); ex = ex->ex_Next)
;
if (ex && (type->Flags & TF_DOTDOTDOT) == 0 && type->Args >= 0)
yerror(ex->ex_LexIdx, EWARN_TOO_MANY_PARAMETERS);
}
while (exp) {
Type *vtype = ActualPassType(type, exp->ex_Type, 1);
if (exp->ex_Type != vtype)
InsertCast(pexp, vtype); /* exp no longer valid */
exp = *pexp;
pexp = &exp->ex_Next;
exp = *pexp;
}
}
void
GenPosInc(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
Exp *e1;
CallLeft();
e1 = exp->ex_ExpL;
if (GenPass == 0) {
#ifdef NOTDEF
if (e1->ex_Stor.st_Type == ST_IntConst) {
e1->ex_Stor.st_IntConst = !e1->ex_Stor.st_IntConst;
*pexp = e1;
return;
}
#endif
exp->ex_Type = e1->ex_Type;
exp->ex_Flags |= e1->ex_Flags & EF_CALL;
if (e1->ex_Token == TokVarRef)
e1->ex_Var->RegFlags |= RF_MODIFIED;
if (e1->ex_Type->Id == TID_FLT) {
exp->ex_Flags |= EF_CALL;
GenFlagCallMade();
}
} else {
Stor con;
if (exp->ex_Type->Id == TID_FLT)
AllocFltConstStor(&con, "1", 1, exp->ex_Type);
else
AllocConstStor(&con, AutoIncDecSize(e1), e1->ex_Type);
CreateUnaryResultStorage(exp, 0);
if ((exp->ex_Flags & EF_RNU) == 0) {
exp->ex_Stor.st_Flags |= e1->ex_Stor.st_Flags & SF_UNSIGNED;
asm_move(exp, &e1->ex_Stor, &exp->ex_Stor);
}
FreeStorage(&e1->ex_Stor);
if (exp->ex_Type->Id == TID_FLT)
asm_fpadd(exp, exp->ex_Type, &con, &e1->ex_Stor, &e1->ex_Stor);
else
asm_add(exp, &con, &e1->ex_Stor, &e1->ex_Stor);
}
}
void
GenPosDec(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
Exp *e1;
CallLeft();
e1 = exp->ex_ExpL;
if (GenPass == 0) {
#ifdef NOTDEF
if (e1->ex_Stor.st_Type == ST_IntConst) {
e1->ex_Stor.st_IntConst = !e1->ex_Stor.st_IntConst;
*pexp = e1;
return;
}
#endif
exp->ex_Flags |= e1->ex_Flags & EF_CALL;
exp->ex_Type = e1->ex_Type;
if (e1->ex_Token == TokVarRef)
e1->ex_Var->RegFlags |= RF_MODIFIED;
if (e1->ex_Type->Id == TID_FLT) {
exp->ex_Flags |= EF_CALL;
GenFlagCallMade();
}
} else {
Stor con;
if (exp->ex_Type->Id == TID_FLT)
AllocFltConstStor(&con, "1", 1, exp->ex_Type);
else
AllocConstStor(&con, AutoIncDecSize(e1), e1->ex_Type);
CreateUnaryResultStorage(exp, 0);
if ((exp->ex_Flags & EF_RNU) == 0) {
exp->ex_Stor.st_Flags |= e1->ex_Stor.st_Flags & SF_UNSIGNED;
asm_move(exp, &e1->ex_Stor, &exp->ex_Stor);
}
FreeStorage(&e1->ex_Stor);
if (exp->ex_Type->Id == TID_FLT)
asm_fpsub(exp, exp->ex_Type, &e1->ex_Stor, &con, &e1->ex_Stor);
else
asm_sub(exp, &e1->ex_Stor, &con, &e1->ex_Stor);
}
}
/*
* For Ind/Elm, exp->ex_Sym (right side is a symbol)
*
* BITFIELD NOTE: Only asm_getind() is guarenteed to leave the
* st_BOffset and st_BSize fields alone.
*/
void
GenStructInd(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
Exp *e1;
int bfo;
CallLeft();
e1 = exp->ex_ExpL;
if (GenPass == 0) {
if (e1->ex_Type->Id != TID_PTR && e1->ex_Type->Id != TID_ARY) {
yerror(e1->ex_LexIdx, EERROR_INDIRECTION_NOT_PTR);
exp->ex_Type = &LongType;
return;
}
exp->ex_Offset = FindStructUnionElm(e1->ex_Type->SubType, exp, &bfo);
if (exp->ex_Type == NULL)
exp->ex_Type = &LongType;
if (exp->ex_Type->Id == TID_BITFIELD) {
BitFieldResultType(pexp, bfo);
exp = *pexp;
e1 = exp->ex_ExpL;
} else {
exp->ex_Stor.st_BOffset = -1;
exp->ex_Stor.st_BSize = -1;
}
/*exp->ex_Flags |= EF_CRES;*/
exp->ex_Flags |= e1->ex_Flags & EF_CALL;
/*
* constant pointer
*/
if (exp->ex_Type->Id != TID_BITFIELD && e1->ex_Stor.st_Type == ST_IntConst) {
if (exp->ex_Type->Id == TID_ARY) {
e1->ex_Stor.st_Type = ST_IntConst;
e1->ex_Stor.st_Size = PTR_SIZE;
e1->ex_Stor.st_IntConst = e1->ex_Stor.st_IntConst + exp->ex_Offset;
e1->ex_Stor.st_Flags |= SF_LEA | SF_UNSIGNED;
} else {
e1->ex_Stor.st_Type = ST_PtrConst;
e1->ex_Stor.st_Size = exp->ex_Type->Size;
e1->ex_Stor.st_Offset = e1->ex_Stor.st_IntConst + exp->ex_Offset;
e1->ex_Stor.st_Flags &= ~SF_LEA;
}
e1->ex_Type = exp->ex_Type;
*pexp = e1;
}
} else {
Stor con;
Stor t;
FreeStorage(&e1->ex_Stor);
if ((exp->ex_Flags & EF_RNU) == 0) {
AllocConstStor(&con, exp->ex_Offset, &LongType);
asm_getindex(exp, e1->ex_Type, &e1->ex_Stor, &con, 1, &t, 1, 0);
FreeStorage(&t);
if (!(exp->ex_Stor.st_Flags & SF_BITFIELD))
exp->ex_Stor.st_BSize = -1;
asm_getind(exp, TypeToPtrType(exp->ex_Type), &t, &exp->ex_Stor, exp->ex_Stor.st_BOffset, exp->ex_Stor.st_BSize, AutoResultStorage(exp));
/*
if (exp->ex_Stor.st_Flags & SF_BITFIELD) {
BitFieldResultExp(exp);
}
*/
}
}
}
void
GenStructElm(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
Exp *e1;
int bfo; /* for bitfields */
CallLeft();
e1 = exp->ex_ExpL;
if (GenPass == 0) {
{
Type *t = e1->ex_Type;
if (t->Id != TID_STRUCT && t->Id != TID_UNION)
yerror(e1->ex_LexIdx, EERROR_NOT_STRUCT_UNION);
exp->ex_Offset = FindStructUnionElm(t, exp, &bfo);
}
if (exp->ex_Type == NULL)
exp->ex_Type = &LongType;
if (exp->ex_Type->Id == TID_BITFIELD) {
BitFieldResultType(pexp, bfo);
exp = *pexp;
e1 = exp->ex_ExpL;
} else {
exp->ex_Stor.st_BOffset = -1;
exp->ex_Stor.st_BSize = -1;
}
/*exp->ex_Flags |= EF_CRES;*/
exp->ex_Flags |= e1->ex_Flags & EF_CALL;
/*
* constant pointer
*/
if (exp->ex_Type->Id != TID_BITFIELD && e1->ex_Stor.st_Type == ST_IntConst) {
if (exp->ex_Type->Id == TID_ARY) {
e1->ex_Stor.st_Type = ST_IntConst;
e1->ex_Stor.st_Size = PTR_SIZE;
e1->ex_Stor.st_IntConst = e1->ex_Stor.st_IntConst + exp->ex_Offset;
e1->ex_Stor.st_Flags |= SF_LEA | SF_UNSIGNED;
} else {
e1->ex_Stor.st_Type = ST_PtrConst;
e1->ex_Stor.st_Size = exp->ex_Type->Size;
e1->ex_Stor.st_Offset = e1->ex_Stor.st_IntConst + exp->ex_Offset;
e1->ex_Stor.st_Flags &= ~SF_LEA;
}
e1->ex_Type = exp->ex_Type;
*pexp = e1;
}
} else {
Stor con;
Stor t;
Stor u;
FreeStorage(&e1->ex_Stor);
if ((exp->ex_Flags & EF_RNU) == 0) {
AllocConstStor(&con, exp->ex_Offset, &LongType);
asm_getlea(exp, &e1->ex_Stor, &t);
FreeStorage(&t);
asm_getindex(exp, TypeToPtrType(e1->ex_Type), &t, &con, 1, &u, 1, 0);
FreeStorage(&u);
if (!(exp->ex_Stor.st_Flags & SF_BITFIELD))
exp->ex_Stor.st_BSize = -1;
asm_getind(exp, TypeToPtrType(exp->ex_Type), &u, &exp->ex_Stor, exp->ex_Stor.st_BOffset, exp->ex_Stor.st_BSize, AutoResultStorage(exp));
/*
if (exp->ex_Stor.st_Flags & SF_BITFIELD) {
BitFieldResultExp(exp);
}
*/
}
}
}
/*
* Handle bitfield result types. If this isn't the LHS of a straight
* assignment, the type is coerced into an integer.
*/
void
BitFieldResultType(pexp, bfo)
Exp **pexp;
int bfo;
{
Exp *exp = *pexp;
exp->ex_Stor.st_BOffset = bfo;
exp->ex_Stor.st_BSize = exp->ex_Type->Size;
exp->ex_Stor.st_Flags |= SF_BITFIELD;
/*
* bit field return type is an integer unless lhs of
* assignment.
*/
if ((exp->ex_Flags & (EF_LHSASSIGN|EF_COND)) == 0) {
InsertNot(pexp);
exp = *pexp;
if (exp->ex_ExpL->ex_Flags & EF_LHSASSEQ)
exp->ex_Flags |= EF_LHSASSEQ;
exp->ex_Func = GenBFExt;
exp->ex_Token = TokBFExt; /* FOR +=, -=, etc... */
if (exp->ex_ExpL->ex_Type->Flags & TF_UNSIGNED)
exp->ex_Type = &ULongType;
else
exp->ex_Type = &LongType;
}
}
#ifdef NOTDEF
/*
* BitFieldResultExp
*/
void
BitFieldResultExp(exp)
Exp *exp;
{
if (exp->ex_Flags & EF_LHSASSIGN)
return;
if (exp->ex_Flags & EF_COND) /* can handle some conds.*/
return;
/*
* but otherwise must store into integer
*/
if (exp->ex_Stor.st_Flags & SF_BITFIELD) {
Stor st = exp->ex_Stor;
FreeStorage(&exp->ex_Stor);
CreateUnaryResultStorage(exp, 0);
asm_bfext(exp, &st, &exp->ex_Stor);
}
}
#endif
void
GenBFExt(pexp)
Exp **pexp;
{
Exp *e1;
Exp *exp = *pexp;
CallLeft();
e1 = exp->ex_ExpL;
if (GenPass == 0) {
;
} else {
Assert(e1->ex_Stor.st_Flags & SF_BITFIELD);
if ((exp->ex_Flags & EF_LHSASSEQ) == 0)
FreeStorage(&e1->ex_Stor);
CreateUnaryResultStorage(exp, 0);
asm_bfext(exp, &e1->ex_Stor, &exp->ex_Stor);
}
}
void
GenArray(pexp)
Exp **pexp;
{
Exp *exp = *pexp;
Exp *e1;
Exp *e2;
CallLeft();
EnsureReturnStorageLeft();
CallRight();
e1 = exp->ex_ExpL;
e2 = exp->ex_ExpR;
if (GenPass == 0) {
Type *t1 = e1->ex_Type;
exp->ex_Flags |= /* EF_CRES |*/ ((e1->ex_Flags | e2->ex_Flags) & EF_CALL);
if (t1->Id == TID_PTR || t1->Id == TID_ARY) {
exp->ex_Type = t1->SubType;
if (e2->ex_Stor.st_Type != ST_IntConst) {
if (asm_mul_requires_call(t1->SubType->Size)) {
exp->ex_Flags |= EF_CALL;
GenFlagCallMade();
}
if (e2->ex_Type->Id != TID_INT)
yerror(e2->ex_LexIdx, EERROR_EXPECTED_INT_TYPE);
}
return;
}
yerror(e1->ex_LexIdx, EERROR_INDIRECTION_NOT_PTR);
exp->ex_Type = &VoidPtrType;
} else {
Stor t;
FreeStorage(&e1->ex_Stor);
FreeStorage(&e2->ex_Stor);
if ((exp->ex_Flags & EF_RNU) == 0) {
asm_getindex(exp, e1->ex_Type, &e1->ex_Stor, &e2->ex_Stor, exp->ex_Type->Size, &t, 1, 0);
FreeStorage(&t);
asm_getind(exp, e1->ex_Type, &t, &exp->ex_Stor, -1, -1, AutoResultStorage(exp));
}
}
}